package com.dark;

import com.tcl.storage.bean.UploadFileResult;
import com.tcl.storage.bean.bpc.FileBlockInfo;
import com.tcl.storage.bean.bpc.FileInfoResult;
import com.tcl.storage.bean.bpc.FileMetaDataInfo;
import com.tcl.storage.client.TclStorageClient;
import com.tcl.storage.client.TclStorageServiceManager;
import com.tcl.storage.exception.StorageException;
import com.tcl.storage.rpc.IBreakpointContinuinglyService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * 这里类主要是用于分块上传文件的工具类。
 *
 * Created by tengxue on 15-10-19.
 */
@Component
public class TclBPCStorageClient {
    private final static Logger logger = LoggerFactory
            .getLogger(TclStorageClient.class);

    private static ApplicationContext context;

    static TclBPCStorageClient instance;

    @Autowired
    public void setApplicationContext(ApplicationContext act) {
        context = act;
    }

    private static IBreakpointContinuinglyService bpcStorageService= TclStorageServiceManager.getInstance().getBreakpointContinuinglyService();

    private TclBPCStorageClient(){

    }

    public static TclBPCStorageClient getInstance() {
        if (instance == null) {
            synchronized (TclBPCStorageClient.class) {
                if (instance != null) {
                    return instance;
                }
                instance = BeanFactoryUtils.beanOfType(context,
                        TclBPCStorageClient.class);
            }
        }
        return instance;
    }

    /**
     * 断点续传文件接口
     *
     * @param fileName 文件名称
     * @throws IOException
     */
    public static UploadFileResult uploadFileBPC(String token,String fileName, InputStream InputStream,
                                                 long length) throws StorageException, IOException {

        String uniqueId = UUID.randomUUID().toString();

        FileMetaDataInfo metaData = new FileMetaDataInfo();
        metaData.setToken(token);
        metaData.setType(1);
        metaData.setFileUniqueId(uniqueId);
        metaData.setFileName(fileName);
        metaData.setContentLenth(length);

        long t0 = System.currentTimeMillis();
        logger.info("{}, metaData: {}", t0, metaData);

        // 上传文件元数据
        FileInfoResult result = bpcStorageService.uploadFileMetaDataInfo(metaData);
        logger.info("{}, upload metaData result: {}", t0, result.toJson());

        if (result.getStatus() != 1) {
            logger.warn("{}, upload metaData failed, return.", t0);
            return null;
        }

        // 每次传1M
        int blockSize = 1048;

        byte[] blockBuff = new byte[blockSize];

        FileBlockInfo blockInfo = new FileBlockInfo();
        blockInfo.setToken(token);
        blockInfo.setType(1);
        blockInfo.setFileUniqueId(uniqueId);

        for (int i = 0; i < length; i += blockSize) {
            //这里为了获取块的实际长度。文件最后一个有可能会小于初始化设定的数据长度。
            int count = IOUtils.read(InputStream, blockBuff, 0, blockSize);
            if (count < blockSize) {
                //如果小于就把真实的大小赋值给数组
                blockBuff = ArrayUtils.subarray(blockBuff, 0, count);
            }
            blockInfo.setCurrentProgress(i);
            blockInfo.setBlockBuff(blockBuff);

            // 上传文件块
            result = bpcStorageService.uploadFileByBlock(blockInfo);
            logger.info("{}, upload blockInfo result: {}", t0, result.toJson());

            if(result.getStatus() != 1) {
                logger.warn("{}, upload blockInfo failed, return. progress: {}", t0, i);
                return null;
            }
        }

        // 文件已经传完
        if (result.getUploadStatus() == 1) {
            UploadFileResult ufr = new UploadFileResult();
            ufr.setStatus(1);
            ufr.setDomain(result.getDomain());
            ufr.setKey(result.getKey());

            logger.info("{}, uploadFile success, cost {}ms", t0, System.currentTimeMillis() - t0);
            return ufr;
        }

        return null;
    }


}
